#include "stdafx.h"
#include "NagiosObject.h"
#include "LineFile.h"

char * Trim(char *s) {
  char *end;

  while(isspace(s[0])) s++;
  if(s[0] == 0) return s;

  end = &s[strlen(s) - 1];
  while(end > s && isspace(end[0])) end--;
  end[1] = 0;

  return s;
}

NagiosItem::NagiosItem()
{
	mName = NULL;
	mValue = NULL;
	mComment = NULL;
	mLine = 0;
	mNext = NULL;
}
NagiosItem::~NagiosItem()
{
	if( mName ) delete mName;
	if( mValue) delete mValue;
	if( mComment) delete mComment;
}


int NagiosItem::Parse(LineFile  * in)
{
	
	char * tmp;
	if( in->ReadLine()==0 ) return 0;
	mLine = in->mLine;
	tmp = Trim(in->mData);
	if( tmp[0]==0 ) return 1;
	if( tmp[0]=='#' ){
		mValue = strdup(tmp+1);
		return 1;
	} 
	char * end;
	end = strstr(tmp,";");
	if( end ){
		mComment = strdup(end+1);
		end[0]=0;
	}
    tmp = Trim(tmp);
	if( tmp[0]==0 ){
		return 1;
	}
	end=tmp;
	while( (end[0]!=0) && (!isspace(end[0])) ) end++;
	char k = end[0];
	end[0]=0;
	mName = strdup(tmp);
	end[0]=k;

	if( mName[0]=='}' ){
		if( mName[1]!=0 ){
			printf("%d: line can not start with }\n",mLine);
			return -2;
		}
		return 1;
	}
	if( mName[0]=='{' ) {
		printf("%d: line can not start with {\n",mLine);
		return -3;
	}
	tmp = end;
	while(isspace(tmp[0])) tmp++;
        mValue = strdup(tmp);
	return 1;
}

int NagiosItem::SetValue(char * value)
{
	if( value == NULL ){
            if( mValue==NULL ) return 0;
	    if( mValue ) delete mValue;
	    mValue= NULL;
	    return 1;
	}
	if( strcmp(mValue,value)==0 ) return 0;
	if( mValue ) delete mValue; 	
	mValue = strdup(value);
	return 1;
}


void NagiosItem::Output(FILE *out)
{
	if( mName){
		fprintf(out,"\t%s ",mName);
        if( mValue ) fprintf(out,"\t %s ",mValue);
		if( mComment ) fprintf(out,";%s",mComment);
		fprintf(out,"\n");
	} else{
		if( mValue) 	fprintf(out,"#%s\n",mValue);
		else if( mComment) fprintf(out,"\t\t\t; %s\n",mComment);
		else fprintf(out,"\n");
	}
}

NagiosObject::NagiosObject()
{
	mNext = NULL;
	mPure = 0;
}

NagiosObject::~NagiosObject(void)
{
	NagiosItem * tmp = mType.mNext;
	NagiosItem * o; 
	while( tmp ) {
		o = tmp;
        tmp = tmp->mNext;
		delete o;
	}
	mType.mNext = NULL;
}
int NagiosObject::IsIDItem(const char * name)
{
	if( strcmp("service_description",name)==0 ) return 1;
	if( strcmp("name",name)==0 ) return 1;
	if( strstr(name,mType.mValue)==name ){
		name += strlen(mType.mValue);
		if( name[0] == '_' ){
			name ++;
			if( strcmp(name ,"name")==0 ) return 1;
		}
	}
	return 0;
}
const char * NagiosObject::GetID()
{
	if( mType.mName == NULL ) return "";
	NagiosItem *  tmp = mType.mNext;
	while(tmp) {
		if( tmp->mName ){
			if( IsIDItem(tmp->mName) ) return tmp->mValue;
		}
		tmp = tmp->mNext;
	}
	return "";
}
const char * NagiosObject::GetValue(char * name)
{
	if( name == NULL ) return NULL;

	if( mType.mName == NULL ) return NULL;
	NagiosItem *  tmp = mType.mNext;
	while( tmp ) {
		if( tmp->mName ) {
			if( strcmp(tmp->mName,name)==0 )	return tmp->mValue;
		}
		tmp = tmp->mNext;
	}
	return NULL;
}
int NagiosObject::SetValue(char * name ,char * value,int bMode)
{
	if( name == NULL ) return 0;
	if( mType.mName == NULL ) return 0;
	NagiosItem *  tmp = mType.mNext;
	NagiosItem *  prev = &mType;
	while( tmp ) {
		if( tmp->mName){
			if( strcmp(tmp->mName,name)==0 ){
				return tmp->SetValue(value);
			}
		}
		prev = tmp;
		tmp = tmp->mNext;
	}
	if( bMode == 0 ){
		tmp = new NagiosItem();
		tmp->mName = strdup(name);
		if( value ) tmp->mValue = strdup(value);
		prev->mNext = tmp;
		return 1;
	}
	return 0;
}
int NagiosObject::RemoveItem(char * name)
{
    if( mType.mName == NULL ) return 0;
    if( name == NULL ) return 0;
    NagiosItem *  tmp = mType.mNext;
	NagiosItem *  prev = &mType;
    while( tmp ) {
		if( tmp->mName  ){
            if( strcmp(tmp->mName,name)==0 ) {
				prev->mNext = tmp->mNext;
				delete tmp;
                return 1;
            }
		}
		prev = tmp;
		tmp = tmp->mNext;
    }
	return 0;
}


void NagiosObject::Output(FILE *out)
{
	if( mType.mName ) {
		fprintf(out,"define %s {\n",mType.mValue);
		NagiosItem *  tmp = mType.mNext;
		while( tmp ) {
			tmp->Output(out);
			tmp = tmp->mNext;
		}
		fprintf(out,"}\n");
	} else {
		if( mType.mValue) 	fprintf(out,"#%s\n",mType.mValue);
		else fprintf(out,"\n");
	}
}
int NagiosObject::Parse(LineFile *in)
{

	int k = mType.Parse(in);
	if( k<1 ) return k;
	//empty line or comment
	if( mType.mName== NULL ) return k;
	//define xxxx { ;xxxxx
	if( strcmp( "define",mType.mName) ){
		printf("%d: expected define here\n",mType.mLine);
		return -4;
	}
	if( mType.mValue == NULL ){
		printf("%d: expected name after define\n",mType.mLine);
		return -5;
	}
	k = strlen(mType.mValue);
	if( k<2 ) {
		printf("%d: expected name after define\n",mType.mLine);
		return -5;
	}
	if( mType.mValue[k-1]!='{' ) {
		printf("%d: expected { after define name\n",mType.mLine);
		return -6;
	}
	mType.mValue[k-1]=0;
	Trim(mType.mValue);

	for(k=0;k<strlen(mType.mValue);k++)
		if((mType.mValue[k]=='{') || (mType.mValue[k]=='}') || isspace(mType.mValue[k]) ) {
			printf("%d: name contain space or { or }\n",mType.mLine);
			return -7;
		}
   NagiosItem * tail = &mType;
   while( !in->eof() ){
		NagiosItem * item = new NagiosItem ();
		k = item->Parse(in);
		if( k==0 )break;		
		if( k<1 ){
			delete item;
			return k;
		}
		if( item->mName == NULL ){
			tail->mNext = item;
			tail = item;
			continue;
		}
		if( strcmp("}",item->mName)==0 ) {
			delete item;
			return 1;
		}
		tail->mNext = item;
		tail = item;
		if( strcmp( "define",item->mName)==0 ){
			printf("%d: unexpected define before define at line %d closed\n",item->mLine,mType.mLine);
			return -4;
		}
	}
	printf("%d: miss } to close\n",mType.mLine);
	return -1;
}
